package com.knowledgegraph.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * 请求日志拦截器
 * 记录所有API请求和响应信息
 */
@Slf4j
@Component
public class LoggingInterceptor implements HandlerInterceptor {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 记录请求开始时间
        request.setAttribute("startTime", System.currentTimeMillis());
        
        // 包装请求和响应以便读取内容
        if (!(request instanceof ContentCachingRequestWrapper)) {
            request = new ContentCachingRequestWrapper(request);
        }
        if (!(response instanceof ContentCachingResponseWrapper)) {
            response = new ContentCachingResponseWrapper(response);
        }
        
        // 记录请求信息
        logRequest(request);
        
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // 计算请求耗时
        Long startTime = (Long) request.getAttribute("startTime");
        long duration = System.currentTimeMillis() - (startTime != null ? startTime : 0);
        
        // 记录响应信息
        logResponse(request, response, duration, ex);
        
        // 如果是包装的响应，需要复制内容到原始响应
        if (response instanceof ContentCachingResponseWrapper) {
            ((ContentCachingResponseWrapper) response).copyBodyToResponse();
        }
    }

    /**
     * 记录请求信息
     */
    private void logRequest(HttpServletRequest request) {
        try {
            Map<String, Object> requestInfo = new HashMap<>();
            requestInfo.put("method", request.getMethod());
            requestInfo.put("url", request.getRequestURL().toString());
            requestInfo.put("uri", request.getRequestURI());
            requestInfo.put("queryString", request.getQueryString());
            requestInfo.put("remoteAddr", getClientIpAddress(request));
            requestInfo.put("userAgent", request.getHeader("User-Agent"));
            
            // 记录请求头
            Map<String, String> headers = new HashMap<>();
            Enumeration<String> headerNames = request.getHeaderNames();
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                // 过滤敏感信息
                if (!headerName.toLowerCase().contains("authorization") && 
                    !headerName.toLowerCase().contains("cookie")) {
                    headers.put(headerName, request.getHeader(headerName));
                }
            }
            requestInfo.put("headers", headers);
            
            // 记录请求参数
            Map<String, String[]> parameters = request.getParameterMap();
            if (!parameters.isEmpty()) {
                requestInfo.put("parameters", parameters);
            }
            
            // 记录请求体（仅对POST、PUT、PATCH请求）
            if ("POST".equalsIgnoreCase(request.getMethod()) || 
                "PUT".equalsIgnoreCase(request.getMethod()) || 
                "PATCH".equalsIgnoreCase(request.getMethod())) {
                
                if (request instanceof ContentCachingRequestWrapper) {
                    ContentCachingRequestWrapper wrapper = (ContentCachingRequestWrapper) request;
                    byte[] content = wrapper.getContentAsByteArray();
                    if (content.length > 0) {
                        String requestBody = new String(content, StandardCharsets.UTF_8);
                        // 限制请求体长度，避免日志过长
                        if (requestBody.length() > 1000) {
                            requestBody = requestBody.substring(0, 1000) + "...";
                        }
                        requestInfo.put("requestBody", requestBody);
                    }
                }
            }
            
            log.info("=== 请求开始 === {}", objectMapper.writeValueAsString(requestInfo));
            
        } catch (Exception e) {
            log.error("记录请求信息失败", e);
        }
    }

    /**
     * 记录响应信息
     */
    private void logResponse(HttpServletRequest request, HttpServletResponse response, long duration, Exception ex) {
        try {
            Map<String, Object> responseInfo = new HashMap<>();
            responseInfo.put("method", request.getMethod());
            responseInfo.put("uri", request.getRequestURI());
            responseInfo.put("status", response.getStatus());
            responseInfo.put("duration", duration + "ms");
            
            // 记录响应头
            Map<String, String> headers = new HashMap<>();
            for (String headerName : response.getHeaderNames()) {
                headers.put(headerName, response.getHeader(headerName));
            }
            responseInfo.put("headers", headers);
            
            // 记录响应体
            if (response instanceof ContentCachingResponseWrapper) {
                ContentCachingResponseWrapper wrapper = (ContentCachingResponseWrapper) response;
                byte[] content = wrapper.getContentAsByteArray();
                if (content.length > 0) {
                    String responseBody = new String(content, StandardCharsets.UTF_8);
                    // 限制响应体长度，避免日志过长
                    if (responseBody.length() > 2000) {
                        responseBody = responseBody.substring(0, 2000) + "...";
                    }
                    responseInfo.put("responseBody", responseBody);
                }
            }
            
            // 记录异常信息
            if (ex != null) {
                responseInfo.put("exception", ex.getMessage());
                log.error("=== 请求异常 === {}", objectMapper.writeValueAsString(responseInfo), ex);
            } else {
                log.info("=== 请求完成 === {}", objectMapper.writeValueAsString(responseInfo));
            }
            
        } catch (Exception e) {
            log.error("记录响应信息失败", e);
        }
    }

    /**
     * 获取客户端真实IP地址
     */
    private String getClientIpAddress(HttpServletRequest request) {
        String xForwardedFor = request.getHeader("X-Forwarded-For");
        if (xForwardedFor != null && !xForwardedFor.isEmpty() && !"unknown".equalsIgnoreCase(xForwardedFor)) {
            return xForwardedFor.split(",")[0].trim();
        }
        
        String xRealIp = request.getHeader("X-Real-IP");
        if (xRealIp != null && !xRealIp.isEmpty() && !"unknown".equalsIgnoreCase(xRealIp)) {
            return xRealIp;
        }
        
        return request.getRemoteAddr();
    }
}